package findEscape;

public class FindEscape {
	symbol.Table escEnv = new symbol.Table();
	
	void traverseVar(int depth, absyn.Var v) {
		if (v instanceof absyn.SimpleVar) traverseVar(depth, (absyn.SimpleVar) v);
		if (v instanceof absyn.FieldVar) traverseVar(depth, (absyn.FieldVar) v);
		if (v instanceof absyn.SubscriptVar) traverseVar(depth, (absyn.SubscriptVar) v);
	}
	
	void traverseVar(int depth, absyn.SimpleVar v) {
		Escape temp;
		
		if ((temp = (Escape) escEnv.get(v.name)) != null && 
				temp.depth < depth)
			temp.setEscape();
	}
	
	void traverseVar(int depth, absyn.SubscriptVar v) {
		traverseVar(depth, v.var);
	}
	
	void traverseVar(int depth, absyn.FieldVar v) {
		traverseVar(depth, v.var);
	}
	
	void traverseExp(int depth, absyn.Exp e) {
		if (e instanceof absyn.VarExp) traverseExp(depth, (absyn.VarExp) e);
		if (e instanceof absyn.CallExp) traverseExp(depth, (absyn.CallExp) e);
		if (e instanceof absyn.OpExp) traverseExp(depth, (absyn.OpExp) e);
		if (e instanceof absyn.RecordExp) traverseExp(depth, (absyn.RecordExp) e);
		if (e instanceof absyn.SeqExp) traverseExp(depth, (absyn.SeqExp) e);
		if (e instanceof absyn.AssignExp) traverseExp(depth, (absyn.AssignExp) e);
		if (e instanceof absyn.IfExp) traverseExp(depth, (absyn.IfExp) e);
		if (e instanceof absyn.WhileExp) traverseExp(depth, (absyn.WhileExp) e);
		if (e instanceof absyn.ForExp) traverseExp(depth, (absyn.ForExp) e);
		if (e instanceof absyn.LetExp) traverseExp(depth, (absyn.LetExp) e);
		if (e instanceof absyn.ArrayExp) traverseExp(depth, (absyn.ArrayExp) e);
	}
	
	void traverseExp(int depth, absyn.VarExp e) {
		traverseVar(depth, e.var);
	}
	
	void traverseExp(int depth, absyn.CallExp e) {
		for (absyn.ExpList temp = e.args; temp != null; temp = temp.tail)
			traverseExp(depth, temp.head);
	}
	
	void traverseExp(int depth, absyn.OpExp e) {
		traverseExp(depth, e.left);
		traverseExp(depth, e.right);
	}
	
	void traverseExp(int depth, absyn.RecordExp e) {
		for (absyn.FieldExpList temp = e.fields; temp != null; temp = temp.tail)
			traverseExp(depth, temp.init);
	}
	
	void traverseExp(int depth, absyn.SeqExp e) {
		for (absyn.ExpList temp = e.list; temp != null; temp = temp.tail)
			traverseExp(depth, temp.head);
	}
	void traverseExp(int depth, absyn.AssignExp e) {
		traverseVar(depth, e.var);
		traverseExp(depth, e.exp);
	}
	
	void traverseExp(int depth, absyn.IfExp e) {
		traverseExp(depth, e.test);
		traverseExp(depth, e.thenclause);
		if (e.elseclause != null) traverseExp(depth, e.elseclause);
	}
	
	void traverseExp(int depth, absyn.WhileExp e) {
		traverseExp(depth, e.test);
		traverseExp(depth, e.body);
	}
	
	void traverseExp(int depth, absyn.ForExp e) {
		traverseExp(depth, e.hi);
		escEnv.beginScope();
		traverseDec(depth, e.var);
		traverseExp(depth, e.body);
		escEnv.endScope();
	}
	
	void traverseExp(int depth, absyn.LetExp e) {
		escEnv.beginScope();
		for (absyn.DecList temp = e.decs; temp != null; temp = temp.tail)
			traverseDec(depth, temp.head);
		traverseExp(depth, e.body);
		escEnv.endScope();
	}
	
	void traverseExp(int depth, absyn.ArrayExp e) {
		traverseExp(depth, e.size);
		traverseExp(depth, e.init);
	}
	
	void traverseDec(int depth, absyn.Dec d) {
		if (d instanceof absyn.VarDec) traverseDec(depth, (absyn.VarDec) d);
		if (d instanceof absyn.FunctionDec)	traverseDec(depth, (absyn.FunctionDec) d);
	}
	
	void traverseDec(int depth, absyn.VarDec d) {
		traverseExp(depth, d.init);
		escEnv.put(d.name, new VarEscape(depth, d));
	}
	
	void traverseDec(int depth, absyn.FunctionDec d) {
		for (absyn.FunctionDec temp = d; temp != null; temp = temp.next) {
			escEnv.beginScope();
			for (absyn.FieldList tfl = temp.params; tfl != null; tfl = tfl.tail)
				escEnv.put(tfl.name, new FormalEscape(depth + 1, tfl));
			traverseExp(depth + 1, temp.body);
			escEnv.endScope();
		}
	}
	
	public FindEscape(absyn.Exp e) {traverseExp(0, e);}
}
